import datetime
import os. path
import sys
import pickle
import backtrader as bt
from backtrader.indicators import EMA

class Teststrategy(bt . strategy):
  def log(self, txt, dt=None):
    ''' Logging function fot this strategy'''
    dt = dt or self. datas[0]. datetime . date(0)
    # print('%s, %s' % (dt.isoformat()， txt))

  @staticmethod
  def percent(today, yes terday ):
    return float(today一yesterday) / today

  def __init__(self):
      self .dataclose = self. datas[0].close
      self .volume = self . datas[0]. volume

      self .order = None
      self .buyprice = None
      self . buycomm = None

      me1 = EMA(self . data, period=12)
      me2 = EMA(self . data, period=26 )
      self .macd = me1 - me2
      self.signal = EMA(self .macd, period=9)

      bt. indicators .MACDHisto(self.data)

  def notify_order(self, order):
      if order . status in [order . Submitted, order . Accepted]:
        return
      if order .status in [order . Completed]: 
        if order . isbuy():
          self . log(
                'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                (order . executed. price,
                order . executed. value,
                order . executed. comm))

          self .buyprice = order . executed. price
          self .buycomm = order . executed . comm
          self .bar_executed_close = self . dataclose[e]
        else: 
          self .log('SELL EXECUTED, price: %.2f, Cost: %.2f, Comm %.2f' %
                  (order . executed. price, 
                  order . executed . value ,
                  order . executed. comm) )
        self .bar_executed = len(self)

      elif order .status in [order . Canceled, order . Margin, order . Rejected]: 
            self.log( ' order Canceled/Margin/Rejected' )
      
      self .order = None

  def notify_trade(self, trade):
      if not trade . isclosed :
        return

      self . log( 'OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                (trade.pnl, trade.pnlcomm)) 
  def next(self):
      self.log( 'Close, %.2f' % self. dataclose[0])
      if self. order:
        return

      if not self . position:
        condition1 = self .macd[-1] - self. signal[-1]
        condition2 = self .macd[0] - self .signal[0]
        if condition1 < 0 and condition2 > 0:
            self.log( 'BUY CREATE, %.2f' % self .dataclose[0])
            self.order = self . buy()
      
      else:
        condition = (self . dataclose[0] - self . bar_executed_close) / self .dataclose[0]
      if condition>0.1 or condition < -0.1:
        self .log('SELL CREATE, %.2f' % self .dataclose[0])
        self .order = self. sell()

def run_cerebro(stock_file, result):
#运行策略
#:param stock_ file: 股票数据文件位置
#:param result: 回测结果存储变量
  cerebro = bt.Cerebro()
  cerebro. addstrategy(Teststrategy)
# 加载数据到模型中
data = bt.feeds.GenericCsvData(
  dataname=stock_file,
  fromdate=datetime . datetime(2010.1, 1),
  todate=datetime . datetime (2020, 4, 25),
  dtformat= ' %Y%m%d',
  datetime=2,
  open=3,
  high=4,
  low=5,
  close=6,
  volume=10,
  reverse=True
)
cerebro.adddata( data )

# 本金10000，每次交易100股
cerebro.broker . setcash( 10000)
cerebro.addsizer(bt . sizers .Fixedsize, stake=100)

# 万五佣金
cerebro. broker . setcommission(commission=0.0005 )

# 运行策略
cerebro. run( ) 

# 剩余本金
money_left = cerebro . broker . getvalue()

# 获取股票名字
stock_name = stock_file.split('\\')[-1].split('.csv')[0]

# 将最终回报率以百分比的形式返回
result[stock_name]= float(money_left - 10000) / 10000
files_path = ' stocks\\'
result = {}

# 遍历所有股票数据
for stock in os.listdir(files_path):
    modpath = os . path. dirname(os . path . abspath( sys . argv[0]))
    datapath = os . path. join(modpath, files_path + stock)
    print( datapath)
    try:
        un_cerebro(datapath,result)
    except Exception as e:
      print(e)

# 计算
pos = []
neg=[]
ten_pos = []
ten_neg = []
for r in result:
    res = result[r] 
    if res>0:
        pos . append(res)
    else:
      neg. append(res)

    if res > 0.1:
      ten_pos . append(r)
    elif res < -0.1:
      ten_neg . append(r)

max_stock = max(result, key=result . get)
print(f'最高收益的股票:{max_stock},达到{result[max_stock]}')
print(f'正收益数量: {len(pos)}, 负收益数量:{len(neg)}')
print(f'+10%数量: {len(ten_pos)}, - 10%数量:{len(ten_neg)}')
print(f'收益10%以上的股票: {ten_pos}' )
